/*
 * Real-time and concurrent programming course, laboratory 3
 * Department of Computer Science, Lund Institute of Technology
 *
 * PP 980812 Created
 * PP 990924 Revised
 */

package todo;

import se.lth.cs.realtime.RTThread;
import done.*;

/**
 * Program 1 of washing machine. Does the following:
 * <UL>
 *   <LI>Lock the hatch.
 *   <LI>Fill water, 10L.
 *   <LI>Heat to 60 degrees.
 *   <LI>Wash at 60 degrees for 30 min.
 *   <LI>Turn off heating, then drain water.
 *   <LI>Rinse 5 times, leave cold water in for 2 minutes on last rinse.
 *   <LI>When all water emptied: centrifuge 5 min.
 *   <LI>Unlock hatch.
 * </UL>
 */
class WashingProgram1 extends WashingProgram {

	// ------------------------------------------------------------- CONSTRUCTOR

	/**
	 * @param   mach             The washing machine to control
	 * @param   speed            Simulation speed
	 * @param   tempController   The TemperatureController to use
	 * @param   waterController  The WaterController to use
	 * @param   spinController   The SpinController to use
	 */
	public WashingProgram1(AbstractWashingMachine mach,
			double speed,
			TemperatureController tempController,
			WaterController waterController,
			SpinController spinController) {
		super(mach, speed, tempController, waterController, spinController);
	}

	// ---------------------------------------------------------- PUBLIC METHODS

	/**
	 * This method contains the actual code for the washing program. Executed
	 * when the start() method is called.
	 */
	protected void wash() throws InterruptedException {
		// Lock
		myMachine.setLock(true);
		
		// Let water in
		myWaterController.putEvent(new WaterEvent(this, WaterEvent.WATER_FILL, 10.0));
		mailbox.doFetch(); // Wait for Ack
		
		// Set water regulation to idle => water valve closes
		myWaterController.putEvent(new WaterEvent(this, WaterEvent.WATER_IDLE, 0.0));

		// Switch on temp regulation
		myTempController.putEvent(new TemperatureEvent(this, TemperatureEvent.TEMP_SET, 60.0));
		
		// Switch on spin
		mySpinController.putEvent(new SpinEvent(this, SpinEvent.SPIN_SLOW));
		RTThread.sleepUntil((long)((30*60*1000)/mySpeed)+System.currentTimeMillis()); // Keep spinning for 30 min
		
		// Switch off temp regulation
		myTempController.putEvent(new TemperatureEvent(this, TemperatureEvent.TEMP_IDLE, 0.0));
		
		// Rinse 5 times
		for(int i=0; i<5; i++){
			// Drain
			System.out.println("Rinse " + i);
			myWaterController.putEvent(new WaterEvent(this, WaterEvent.WATER_DRAIN, 0.0));
			mailbox.doFetch(); // Wait for Ack
			
			// Set water regulation to idle => drain pump stops
			myWaterController.putEvent(new WaterEvent(this, WaterEvent.WATER_IDLE, 0.0));
			
			// Let water in
			myWaterController.putEvent(new WaterEvent(this, WaterEvent.WATER_FILL, 10.0));
			mailbox.doFetch(); // Wait for Ack
			
			// Set water regulation to idle => water valve closes
			myWaterController.putEvent(new WaterEvent(this, WaterEvent.WATER_IDLE, 0.0));
		}
		
		// Soak for 2 min
		RTThread.sleepUntil((long)((2*60*1000)/mySpeed)+System.currentTimeMillis());
		
		// Switch off spin
		mySpinController.putEvent(new SpinEvent(this, SpinEvent.SPIN_OFF));

		// Drain
		myWaterController.putEvent(new WaterEvent(this, WaterEvent.WATER_DRAIN, 0.0));
		mailbox.doFetch(); // Wait for Ack
		
		// Centrifuge
		mySpinController.putEvent(new SpinEvent(this, SpinEvent.SPIN_FAST));
		RTThread.sleepUntil((long)((5*60*1000)/mySpeed)+System.currentTimeMillis()); // Keep spinning for 5 min
		
		// Switch off spin
		mySpinController.putEvent(new SpinEvent(this, SpinEvent.SPIN_OFF));
		
		// Set water regulation to idle => drain pump stops
		myWaterController.putEvent(new WaterEvent(this, WaterEvent.WATER_IDLE, 0.0));

		// Unlock
		myMachine.setLock(false);		
	}
}
